from typing import Union
from bpy.types import Node, Material, NodeTree, UILayout


    
def get_node_index_or_identifier_by(mode:str, search_type:str, socket_type:str, node:Node, search_type_name:str, debug:bool=False) -> Union[int, str]:
    
    """
        INFO: \n
        mode = puede ser "index" o "identifier" \n
        search_type = puede ser "name" o "type" para compararlos con search_type_name (por ejemplo Radius). \n
        socket_type = puede ser "inputs" o "outputs"
    """
    result = None
    
    # NOTA: ¿Que significa que estén los sockets enabled?, algunos nodos tienen varios "estados" y por cada estado cambian sus sockets visibles.
    # Con .enabled nos aseguramos de que solo usemos los sockets que se están viendo el el nodo en ese momento, independientemente del 
    # resto de sockets ocultos que tenga el nodo.
    
    if mode == "index":
        result = next((i for i, socket in enumerate(getattr(node, socket_type)) if socket.enabled and getattr(socket, search_type) == search_type_name), None)
    
    elif mode == "identifier":
        result = next((socket.identifier for socket in getattr(node, socket_type) if socket.enabled and getattr(socket, search_type) == search_type_name), None)
            
    if debug:
        print("---------------------------------")
        print("node.name:", node.name)
        print("search_type:", search_type)
        print("socket_type:", socket_type)
        print("search_type_name:", search_type_name)
        print("result:", result)

    return result

    
    
def color_ramp_ui(context, layout, material: Material, levels: list = []) -> None:
    
    # Obtén el material y los nombres de los nodos
    material = levels[0]
    node_names = levels[1:]

    # Inicializa el nodo actual con el material
    shader_node = material.node_tree

    # Itera sobre los nombres de los nodos
    for node_name in node_names:
        # Verifica si el nodo actual tiene un subnodo con el nombre dado
        if node_name in shader_node.nodes:
            shader_node = shader_node.nodes[node_name]
    
    # print("Nodo final:", shader_node) 
    if shader_node:

        # puntero al shader:
        layout.context_pointer_set("node", shader_node)

        if hasattr(shader_node, "draw_buttons_ext"):
            shader_node.draw_buttons_ext(context, layout)

        elif hasattr(shader_node, "draw_buttons"):
            shader_node.draw_buttons(context, layout)


def node_prop_visualize_in_ui(layout:UILayout, node_tree:NodeTree, target_node_name:str, target_io_type:str, prop_name:str, ui_name:str, index:int=None) -> NodeTree:
    node = next((node for node in node_tree.nodes if node.name.startswith(target_node_name)), None)
    if node:

        # Ahora el usuario puede indicar el indice (porque un Multiply tiene dos nombres Value, entonces puedes decir 0 o 1 para elegirlos)
        if not index:
            index = get_node_index_or_identifier_by("index", "name", target_io_type, node, prop_name, debug=False)
        
        if index is not None:
            io = getattr(node, target_io_type)
            layout.prop(io[index], "default_value", text=ui_name)